package com.ikas.ai.framework.node.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.ikas.ai.framework.core.model.BatchDataFunction;
import com.ikas.ai.framework.core.model.NodeInputVariables;
import com.ikas.ai.framework.core.model.PageBatchOutput;
import com.ikas.ai.framework.flow.ScoreFlow;
import com.ikas.ai.framework.node.NodeType;
import com.ikas.ai.framework.statistics.StatisticType;
import com.ikas.ai.framework.statistics.function.*;
import com.ikas.ai.framework.utils.LoadDataUtils;
import com.ikas.ai.utils.CollectionUtil;
import lombok.extern.slf4j.Slf4j;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @Description: 数学统计算法节点
 * @Author: qi.yilai
 * @Date: 2023/10/27 16:33
 * @Version: 1.0.0
 **/
@Slf4j
public class MathStatisticsNode extends AbstractNode<JSONObject> {
    private static final String METE_CODE = "meteCode";
    private static final String COLUMN = "column";
    private static final String TYPE = "type";
    private static final String COLUMN_TIME_SUFFIX = "_time";

    private JSONArray targetColumns;
    private List<String> numberFunctions;
    private List<String> stringFunctions;

    public MathStatisticsNode(ScoreFlow scoreFlow, JSONArray targetColumns, List<String> numberFunctions, List<String> stringFunctions, Long nodeId, Long nodeInstanceId, String name) {
        super(scoreFlow, nodeId, nodeInstanceId, name);
        this.targetColumns = targetColumns;
        this.numberFunctions = numberFunctions;
        this.stringFunctions = stringFunctions;
    }

    @Override
    public NodeType type() {
        return NodeType.MATCH_STATISTICS;
    }

    @Override
    JSONObject doExecute() {
        JSONObject all = new JSONObject();
        Set<BatchDataFunction> set = previous.getFunctions();
        set.forEach(batchDataFunction -> {
            all.putAll(calculate(batchDataFunction));
        });
        return all;
    }

    @Override
    public NodeInputVariables outVariables() {
        NodeInputVariables nodeInputVariables = NodeInputVariables.copy(previous);
        nodeInputVariables.clearFunctions();
        mergeData(nodeInputVariables, result);
        return nodeInputVariables;
    }

    private JSONObject calculate(BatchDataFunction batchDataFunction) {
        JSONObject jsonObject = batchDataFunction.getMeteData();
        if (Objects.isNull(jsonObject)) {
            return new JSONObject();
        }
        if (!jsonObject.containsKey(METE_CODE)) {
            return new JSONObject();
        }
        // 找到测点值
        String meteCode = jsonObject.getString(METE_CODE);
        // 找到对应的列
        JSONObject columnObject = findColumn(targetColumns, meteCode);
        if (Objects.isNull(columnObject)) {
            return new JSONObject();
        }
        String type = columnObject.getString(TYPE);
        boolean isNumber = isNumber(type);

        JSONObject result;

        // 一次性加载所有的数据 or 2=按数据量取数
        if (loadByOnce(numberFunctions) || batchDataFunction.getQueryType() == 2) {
            Map<String, List<String>> dataMap = LoadDataUtils.loadAllData(batchDataFunction);
            if (CollectionUtil.isEmpty(dataMap)) {
                warningMessage = "获取批量测点数据为空，无法进行统计";
            }
            if (isNumber) {
                // 计算数值相关的统计方法
                result = doCalculateForNumber(meteCode, dataMap);
            } else {
                // 计算字符串相关的统计方法
                result = doCalculateForString(meteCode, dataMap);
            }
        } else {
            // 分页处理
            if (isNumber) {
                result = doCalculateForNumberByPage(meteCode, batchDataFunction);
            } else {
                result = doCalculateForStringByPage(meteCode, batchDataFunction);
            }
        }
        log.info("计算结果统计变量有：{}", result.toJSONString());
        return result;
    }

    /**
     * 一次性加载计算数值
     *
     * @param meteCode
     * @param dataMap
     * @return
     */
    private JSONObject doCalculateForNumber(String meteCode, Map<String, List<String>> dataMap) {
        List<String> columns = Lists.newArrayList(meteCode);
        if (targetColumnContain(meteCode + COLUMN_TIME_SUFFIX)) {
            columns.add(meteCode + COLUMN_TIME_SUFFIX);
        }
        JSONObject result = new JSONObject();
        columns.stream().forEach(columnName -> {
            result.putAll(doCalculateColumnForNumber(columnName, dataMap.get(columnName)));
        });
        return result;
    }

    private JSONObject doCalculateColumnForNumber(String columnName, List<String> fromData) {
        if (CollectionUtil.isEmpty(fromData)) {
            return handleStatisticsNullResult(columnName, true);
        }
        List<Double> dataList = fromData.stream().map(Double::valueOf).collect(Collectors.toList());
        // 是否已经计算统计数量、求和
        boolean counted = false;
        boolean sumDone = false;
        long count = 0;
        double sum = 0;
        List<String> restFunctions = Lists.newArrayList();
        JSONObject result = new JSONObject();

        // 先处理 统计总数和求和(优化性能)
        for (String func : numberFunctions) {
            StatisticType statisticType = StatisticType.of(func);
            if (Objects.isNull(statisticType)) {
                throw new UnsupportedOperationException(String.format("暂不支持%s统计方法", func));
            }
            if (statisticType == StatisticType.COUNT) {
                count = LoadDataUtils.getFunc(statisticType, CountCalcFunction.class).calculate(dataList);
                result.put(columnName + "_" + func, count);
                counted = true;
            } else if (statisticType == StatisticType.SUM) {
                sum = LoadDataUtils.getFunc(statisticType, SumCalcFunction.class).calculate(dataList);
                result.put(columnName + "_" + func, sum);
                sumDone = true;
            } else {
                restFunctions.add(func);
            }
        }

        for (String func : restFunctions) {
            StatisticType statisticType = StatisticType.of(func);
            if (Objects.isNull(statisticType)) {
                throw new UnsupportedOperationException(String.format("暂不支持%s统计方法", func));
            }
            Number value = null;
            if (statisticType == StatisticType.NULL_COUNT) {
                value = LoadDataUtils.getFunc(statisticType, NullCountCalcFunction.class).calculate(dataList);
            } else if (statisticType == StatisticType.NOT_NULL_COUNT) {
                value = LoadDataUtils.getFunc(statisticType, NotNullCountCalcFunction.class).calculate(dataList);
            } else if (statisticType == StatisticType.NULL_RATIO) {
                value = LoadDataUtils.getFunc(statisticType, NullRatioCalcFunction.class).calculate(dataList);
            } else if (statisticType == StatisticType.NOT_NULL_RATIO) {
                value = LoadDataUtils.getFunc(statisticType, NotNullRatioCalcFunction.class).calculate(dataList);
            } else if (statisticType == StatisticType.MAX) {
                value = LoadDataUtils.getFunc(statisticType, MaxCalcFunction.class).calculate(dataList);
            } else if (statisticType == StatisticType.MIN) {
                value = LoadDataUtils.getFunc(statisticType, MinCalcFunction.class).calculate(dataList);
            } else if (statisticType == StatisticType.AVG) {
                if (counted && sumDone) {
                    value = LoadDataUtils.getFunc(statisticType, AvgCalcFunction.class).calculate(dataList, sum, count);
                } else {
                    value = LoadDataUtils.getFunc(statisticType, AvgCalcFunction.class).calculate(dataList);
                }
            } else if (statisticType == StatisticType.STANDARD_DEVIATION) {
                if (counted && sumDone) {
                    value = LoadDataUtils.getFunc(statisticType, StandardDeviationCalcFunction.class).calculate(dataList, sum, count);
                } else {
                    value = LoadDataUtils.getFunc(statisticType, StandardDeviationCalcFunction.class).calculate(dataList);
                }
            } else if (statisticType == StatisticType.MEDIAN) {
                value = LoadDataUtils.getFunc(statisticType, MedianCalcFunction.class).calculate(dataList);
            }
            result.put(columnName + "_" + func, value);
        }
        return result;
    }

    /**
     * 一次性加载，计算字符串统计方法
     *
     * @param meteCode
     * @param dataMap
     * @return
     */
    private JSONObject doCalculateForString(String meteCode, Map<String, List<String>> dataMap) {
        JSONObject result = new JSONObject();
        if (CollectionUtil.isEmpty(dataMap.get(meteCode))) {
            return handleStatisticsNullResult(meteCode, false);
        }
        List<Double> dataList = dataMap.get(meteCode).stream().map(Double::valueOf).collect(Collectors.toList());
        for (String func : stringFunctions) {
            StatisticType statisticType = StatisticType.of(func);
            if (Objects.isNull(statisticType)) {
                throw new UnsupportedOperationException(String.format("暂不支持%s统计方法", func));
            }
            Number value;
            if (statisticType == StatisticType.NULL_COUNT) {
                value = LoadDataUtils.getFunc(statisticType, NullCountCalcFunction.class).calculate(dataList);
            } else if (statisticType == StatisticType.NOT_NULL_COUNT) {
                value = LoadDataUtils.getFunc(statisticType, NotNullCountCalcFunction.class).calculate(dataList);
            } else if (statisticType == StatisticType.NULL_RATIO) {
                value = LoadDataUtils.getFunc(statisticType, NullRatioCalcFunction.class).calculate(dataList);
            } else if (statisticType == StatisticType.NOT_NULL_RATIO) {
                value = LoadDataUtils.getFunc(statisticType, NotNullRatioCalcFunction.class).calculate(dataList);
            } else if (statisticType == StatisticType.COUNT) {
                value = LoadDataUtils.getFunc(statisticType, CountCalcFunction.class).calculate(dataList);
            } else {
                throw new UnsupportedOperationException("字符串统计方法只支持 总和、空值数、非空数、空值比例、非空比例");
            }
            result.put(meteCode + "_" + func, value);
        }

        if (targetColumnContain(meteCode + COLUMN_TIME_SUFFIX)) {
            result.putAll(doCalculateColumnForNumber(meteCode + COLUMN_TIME_SUFFIX, dataMap.get(meteCode + COLUMN_TIME_SUFFIX)));
        }
        return result;
    }

    /**
     * 分页加载计算数值统计方法
     *
     * @param meteCode
     * @return
     */
    private JSONObject doCalculateForNumberByPage(String meteCode, BatchDataFunction batchDataFunction) {
        int page = 1;
        JSONObject result = new JSONObject();

        double sum = 0;
        long count = 0;
        long nullCount = 0;
        long nonNullCount = 0;
        Double max = null;
        Double min = null;

        double timeSum = 0;
        long timeCount = 0;
        long timeNullCount = 0;
        long timeNonNullCount = 0;
        Double timeMax = null;
        Double timeMin = null;

        String timeColumn = meteCode + COLUMN_TIME_SUFFIX;
        boolean containTimeColumn = targetColumnContain(timeColumn);

        while (true) {
            PageBatchOutput pageBatchOutput = LoadDataUtils.loadPageData(batchDataFunction, page);
            Map<String, List<String>> dataMap = pageBatchOutput.getDataMap();
            if (CollectionUtil.isEmpty(dataMap) || CollectionUtil.isEmpty(dataMap.get(meteCode)) || CollectionUtil.isEmpty(dataMap.get(timeColumn))) {
                warningMessage = "获取批量测点数据为空，无法进行统计";
                return handleStatisticsNullResultForMeteCode(meteCode, containTimeColumn, true);
            }
            List<Double> dataList = dataMap.get(meteCode).stream().map(Double::valueOf).collect(Collectors.toList());
            if (numberFunctions.contains(StatisticType.COUNT.getMethod()) ||
                    numberFunctions.contains(StatisticType.NULL_RATIO.getMethod()) ||
                    numberFunctions.contains(StatisticType.NOT_NULL_RATIO.getMethod()) ||
                    numberFunctions.contains(StatisticType.AVG.getMethod())) {
                count += LoadDataUtils.getFunc(StatisticType.COUNT, CountCalcFunction.class).calculate(dataList);
            }
            if (numberFunctions.contains(StatisticType.NULL_COUNT.getMethod()) || numberFunctions.contains(StatisticType.NULL_RATIO.getMethod())) {
                nullCount += LoadDataUtils.getFunc(StatisticType.NULL_COUNT, NullCountCalcFunction.class).calculate(dataList);
            }

            if (numberFunctions.contains(StatisticType.NOT_NULL_COUNT.getMethod()) || numberFunctions.contains(StatisticType.NOT_NULL_RATIO.getMethod())) {
                nonNullCount += LoadDataUtils.getFunc(StatisticType.NOT_NULL_COUNT, NotNullCountCalcFunction.class).calculate(dataList);
            }

            if (numberFunctions.contains(StatisticType.SUM.getMethod()) || numberFunctions.contains(StatisticType.AVG.getMethod())) {
                sum += LoadDataUtils.getFunc(StatisticType.SUM, SumCalcFunction.class).calculate(dataList);
            }

            if (numberFunctions.contains(StatisticType.MAX.getMethod())) {
                double maxTmp = LoadDataUtils.getFunc(StatisticType.MAX, MaxCalcFunction.class).calculate(dataList);
                if (Objects.isNull(max)) {
                    max = maxTmp;
                } else {
                    max = (maxTmp > max) ? maxTmp : max;
                }
            }

            if (numberFunctions.contains(StatisticType.MIN.getMethod())) {
                double minTmp = LoadDataUtils.getFunc(StatisticType.MIN, MinCalcFunction.class).calculate(dataList);
                if (Objects.isNull(min)) {
                    min = minTmp;
                } else {
                    min = (minTmp > min) ? min : minTmp;
                }
            }

            // 判断 测点_time 是否存在
            if (containTimeColumn) {
                dataList = dataMap.get(timeColumn).stream().map(Double::valueOf).collect(Collectors.toList());
                if (numberFunctions.contains(StatisticType.COUNT.getMethod()) ||
                        numberFunctions.contains(StatisticType.NULL_RATIO.getMethod()) ||
                        numberFunctions.contains(StatisticType.NOT_NULL_RATIO.getMethod()) ||
                        numberFunctions.contains(StatisticType.AVG.getMethod())) {
                    timeCount += LoadDataUtils.getFunc(StatisticType.COUNT, CountCalcFunction.class).calculate(dataList);
                }
                if (numberFunctions.contains(StatisticType.NULL_COUNT.getMethod()) || numberFunctions.contains(StatisticType.NULL_RATIO.getMethod())) {
                    timeNullCount += LoadDataUtils.getFunc(StatisticType.NULL_COUNT, NullCountCalcFunction.class).calculate(dataList);
                }

                if (numberFunctions.contains(StatisticType.NOT_NULL_COUNT.getMethod()) || numberFunctions.contains(StatisticType.NOT_NULL_RATIO.getMethod())) {
                    timeNonNullCount += LoadDataUtils.getFunc(StatisticType.NOT_NULL_COUNT, NotNullCountCalcFunction.class).calculate(dataList);
                }

                if (numberFunctions.contains(StatisticType.SUM.getMethod()) || numberFunctions.contains(StatisticType.AVG.getMethod())) {
                    timeSum += LoadDataUtils.getFunc(StatisticType.SUM, SumCalcFunction.class).calculate(dataList);
                }

                if (numberFunctions.contains(StatisticType.MAX.getMethod())) {
                    double maxTmp = LoadDataUtils.getFunc(StatisticType.MAX, MaxCalcFunction.class).calculate(dataList);
                    if (Objects.isNull(timeMax)) {
                        timeMax = maxTmp;
                    } else {
                        timeMax = (maxTmp > timeMax) ? maxTmp : timeMax;
                    }
                }

                if (numberFunctions.contains(StatisticType.MIN.getMethod())) {
                    double minTmp = LoadDataUtils.getFunc(StatisticType.MIN, MinCalcFunction.class).calculate(dataList);
                    if (Objects.isNull(timeMin)) {
                        timeMin = minTmp;
                    } else {
                        timeMin = (minTmp > timeMin) ? timeMin : minTmp;
                    }
                }
            }

            if (!pageBatchOutput.toBeContinue()) {
                break;
            }
            page++;
        }

        for (String func : numberFunctions) {
            StatisticType statisticType = StatisticType.of(func);
            if (Objects.isNull(statisticType)) {
                throw new UnsupportedOperationException(String.format("暂不支持%s统计方法", func));
            }
            if (statisticType == StatisticType.STANDARD_DEVIATION || statisticType == StatisticType.MEDIAN) {
                throw new UnsupportedOperationException("分页不支持标准差和中位数计算");
            }
            Number value = null;
            if (statisticType == StatisticType.COUNT) {
                value = count;
            } else if (statisticType == StatisticType.NULL_COUNT) {
                value = nullCount;
            } else if (statisticType == StatisticType.NOT_NULL_COUNT) {
                value = nonNullCount;
            } else if (statisticType == StatisticType.NULL_RATIO) {
                value = nullCount * 1.0 / count;
            } else if (statisticType == StatisticType.NOT_NULL_RATIO) {
                value = nonNullCount * 1.0 / count;
            } else if (statisticType == StatisticType.SUM) {
                value = sum;
            } else if (statisticType == StatisticType.MAX) {
                value = max;
            } else if (statisticType == StatisticType.MIN) {
                value = min;
            } else if (statisticType == StatisticType.AVG) {
                value = sum / count;
            }
            result.put(meteCode + "_" + func, value);

            if (containTimeColumn) {
                if (statisticType == StatisticType.COUNT) {
                    value = timeCount;
                } else if (statisticType == StatisticType.NULL_COUNT) {
                    value = timeNullCount;
                } else if (statisticType == StatisticType.NOT_NULL_COUNT) {
                    value = timeNonNullCount;
                } else if (statisticType == StatisticType.NULL_RATIO) {
                    value = timeNullCount * 1.0 / timeCount;
                } else if (statisticType == StatisticType.NOT_NULL_RATIO) {
                    value = timeNonNullCount * 1.0 / timeCount;
                } else if (statisticType == StatisticType.SUM) {
                    value = timeSum;
                } else if (statisticType == StatisticType.MAX) {
                    value = timeMax;
                } else if (statisticType == StatisticType.MIN) {
                    value = timeMin;
                } else if (statisticType == StatisticType.AVG) {
                    value = timeSum / timeCount;
                }
                result.put(timeColumn + "_" + func, value);
            }
        }
        return result;
    }


    /**
     * 分页加载计算字符串统计方法
     *
     * @param meteCode
     * @return
     */
    private JSONObject doCalculateForStringByPage(String meteCode, BatchDataFunction batchDataFunction) {
        int page = 1;
        JSONObject result = new JSONObject();

        long count = 0;
        long nullCount = 0;
        long nonNullCount = 0;

        double timeSum = 0;
        long timeCount = 0;
        long timeNullCount = 0;
        long timeNonNullCount = 0;
        Double timeMax = null;
        Double timeMin = null;

        String timeColumn = meteCode + COLUMN_TIME_SUFFIX;
        boolean containTimeColumn = targetColumnContain(timeColumn);

        while (true) {
            PageBatchOutput pageBatchOutput = LoadDataUtils.loadPageData(batchDataFunction, page);
            Map<String, List<String>> dataMap = pageBatchOutput.getDataMap();
            if (CollectionUtil.isEmpty(dataMap) || CollectionUtil.isEmpty(dataMap.get(meteCode)) || CollectionUtil.isEmpty(dataMap.get(timeColumn))) {
                warningMessage = "获取批量测点数据为空，无法进行统计";
                return handleStatisticsNullResultForMeteCode(meteCode, containTimeColumn, false);
            }
            List<String> data = dataMap.get(meteCode);
            if (stringFunctions.contains(StatisticType.COUNT.getMethod()) ||
                    stringFunctions.contains(StatisticType.NULL_RATIO.getMethod()) ||
                    stringFunctions.contains(StatisticType.NOT_NULL_RATIO.getMethod())) {
                count += LoadDataUtils.getFunc(StatisticType.COUNT, CountCalcFunction.class).calculate(data);
            }
            if (stringFunctions.contains(StatisticType.NULL_COUNT.getMethod()) || stringFunctions.contains(StatisticType.NULL_RATIO.getMethod())) {
                nullCount += LoadDataUtils.getFunc(StatisticType.NULL_COUNT, NullCountCalcFunction.class).calculate(data);
            }

            if (stringFunctions.contains(StatisticType.NOT_NULL_COUNT.getMethod()) || stringFunctions.contains(StatisticType.NOT_NULL_RATIO.getMethod())) {
                nonNullCount += LoadDataUtils.getFunc(StatisticType.NOT_NULL_COUNT, NotNullCountCalcFunction.class).calculate(data);
            }

            // 判断 测点_time 是否存在
            if (containTimeColumn) {
                List<Double> dataList = dataMap.get(timeColumn).stream().map(Double::valueOf).collect(Collectors.toList());
                if (numberFunctions.contains(StatisticType.COUNT.getMethod()) ||
                        numberFunctions.contains(StatisticType.NULL_RATIO.getMethod()) ||
                        numberFunctions.contains(StatisticType.NOT_NULL_RATIO.getMethod()) ||
                        numberFunctions.contains(StatisticType.AVG.getMethod())) {
                    timeCount += LoadDataUtils.getFunc(StatisticType.COUNT, CountCalcFunction.class).calculate(dataList);
                }
                if (numberFunctions.contains(StatisticType.NULL_COUNT.getMethod()) || numberFunctions.contains(StatisticType.NULL_RATIO.getMethod())) {
                    timeNullCount += LoadDataUtils.getFunc(StatisticType.NULL_COUNT, NullCountCalcFunction.class).calculate(dataList);
                }

                if (numberFunctions.contains(StatisticType.NOT_NULL_COUNT.getMethod()) || numberFunctions.contains(StatisticType.NOT_NULL_RATIO.getMethod())) {
                    timeNonNullCount += LoadDataUtils.getFunc(StatisticType.NOT_NULL_COUNT, NotNullCountCalcFunction.class).calculate(dataList);
                }

                if (numberFunctions.contains(StatisticType.SUM.getMethod()) || numberFunctions.contains(StatisticType.AVG.getMethod())) {
                    timeSum += LoadDataUtils.getFunc(StatisticType.SUM, SumCalcFunction.class).calculate(dataList);
                }

                if (numberFunctions.contains(StatisticType.MAX.getMethod())) {
                    double maxTmp = LoadDataUtils.getFunc(StatisticType.MAX, MaxCalcFunction.class).calculate(dataList);
                    if (Objects.isNull(timeMax)) {
                        timeMax = maxTmp;
                    } else {
                        timeMax = (maxTmp > timeMax) ? maxTmp : timeMax;
                    }
                }

                if (numberFunctions.contains(StatisticType.MIN.getMethod())) {
                    double minTmp = LoadDataUtils.getFunc(StatisticType.MIN, MinCalcFunction.class).calculate(dataList);
                    if (Objects.isNull(timeMin)) {
                        timeMin = minTmp;
                    } else {
                        timeMin = (minTmp > timeMin) ? timeMin : minTmp;
                    }
                }
            }

            if (!pageBatchOutput.toBeContinue()) {
                break;
            }
            page++;
        }

        for (String func : stringFunctions) {
            StatisticType statisticType = StatisticType.of(func);
            if (Objects.isNull(statisticType)) {
                throw new UnsupportedOperationException(String.format("暂不支持%s统计方法", func));
            }
            if (statisticType == StatisticType.STANDARD_DEVIATION || statisticType == StatisticType.MEDIAN) {
                throw new UnsupportedOperationException("分页不支持标准差和中位数计算");
            }
            Number value;
            if (statisticType == StatisticType.COUNT) {
                value = count;
            } else if (statisticType == StatisticType.NULL_COUNT) {
                value = nullCount;
            } else if (statisticType == StatisticType.NOT_NULL_COUNT) {
                value = nonNullCount;
            } else if (statisticType == StatisticType.NULL_RATIO) {
                value = nullCount * 1.0 / count;
            } else if (statisticType == StatisticType.NOT_NULL_RATIO) {
                value = nonNullCount * 1.0 / count;
            } else {
                throw new UnsupportedOperationException("字符串统计方法只支持 总和、空值数、非空数、空值比例、非空比例");
            }
            result.put(meteCode + "_" + func, value);

            if (containTimeColumn) {
                if (statisticType == StatisticType.COUNT) {
                    value = timeCount;
                } else if (statisticType == StatisticType.NULL_COUNT) {
                    value = timeNullCount;
                } else if (statisticType == StatisticType.NOT_NULL_COUNT) {
                    value = timeNonNullCount;
                } else if (statisticType == StatisticType.NULL_RATIO) {
                    value = timeNullCount * 1.0 / timeCount;
                } else if (statisticType == StatisticType.NOT_NULL_RATIO) {
                    value = timeNonNullCount * 1.0 / timeCount;
                } else if (statisticType == StatisticType.SUM) {
                    value = timeSum;
                } else if (statisticType == StatisticType.MAX) {
                    value = timeMax;
                } else if (statisticType == StatisticType.MIN) {
                    value = timeMin;
                } else if (statisticType == StatisticType.AVG) {
                    value = timeSum / timeCount;
                }
                result.put(timeColumn + "_" + func, value);
            }
        }
        return result;
    }

    /**
     * 处理没有数据的时候返回空
     *
     * @param columnName
     * @param isNumber
     * @return
     */
    private JSONObject handleStatisticsNullResult(String columnName, boolean isNumber) {
        JSONObject jsonObject = new JSONObject();
        if (isNumber) {
            numberFunctions.stream().forEach(fun -> {
                jsonObject.put(columnName + "_" + fun, null);
            });
        } else {
            stringFunctions.stream().forEach(fun -> {
                jsonObject.put(columnName + "_" + fun, null);
            });
        }
        return jsonObject;
    }

    /**
     * 针对测点没有数据返回空
     *
     * @param meteCode
     * @param containTimeColumn
     * @param isNumber
     * @return
     */
    private JSONObject handleStatisticsNullResultForMeteCode(String meteCode, boolean containTimeColumn, boolean isNumber) {
        JSONObject jsonObject = new JSONObject();
        jsonObject.putAll(handleStatisticsNullResult(meteCode, isNumber));
        if (containTimeColumn) {
            jsonObject.putAll(handleStatisticsNullResult(meteCode + COLUMN_TIME_SUFFIX, true));
        }
        return jsonObject;
    }

    private JSONObject findColumn(JSONArray columns, String meteCode) {
        for (int i = 0; i < columns.size(); i++) {
            JSONObject jsonObject = columns.getJSONObject(i);
            if (jsonObject.getString(COLUMN).equals(meteCode) || jsonObject.getString(COLUMN).equals(meteCode + COLUMN_TIME_SUFFIX)) {
                return jsonObject;
            }
        }
        return null;
    }

    private boolean isNumber(String type) {
        return "int".equals(type) || "bigint".equals(type) ||
                "float".equals(type) || "double".equals(type);
    }

    /**
     * 判断是否一次性加载，求平均值和标准差都必须一次性加载所有数据
     */
    private boolean loadByOnce(List<String> functions) {
        return functions.contains(StatisticType.STANDARD_DEVIATION.getMethod()) || functions.contains(StatisticType.MEDIAN.getMethod());
    }

    /**
     * 是否包含目标列
     *
     * @param column
     * @return
     */
    private boolean targetColumnContain(String column) {
        for (int i = 0; i < targetColumns.size(); i++) {
            JSONObject obj = targetColumns.getJSONObject(i);
            if (obj.get(COLUMN).equals(column)) {
                return true;
            }
        }
        return false;
    }
}
